/*
 * Copyright (C) 2016 Nishant Srivastava
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.nisrulz.senseysample;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.AbsButton;
import ohos.agp.components.ComponentState;
import ohos.agp.components.Switch;
import ohos.agp.components.Text;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.StateElement;
import ohos.agp.window.service.WindowManager;
import ohos.bundle.IBundleManager;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import com.github.nisrulz.sensey.ChopDetector;
import com.github.nisrulz.sensey.FlipDetector;
import com.github.nisrulz.sensey.LightDetector;
import com.github.nisrulz.sensey.MovementDetector;
import com.github.nisrulz.sensey.OrientationDetector;
import com.github.nisrulz.sensey.PickupDeviceDetector;
import com.github.nisrulz.sensey.ProximityDetector;
import com.github.nisrulz.sensey.RotationAngleDetector;
import com.github.nisrulz.sensey.ScoopDetector;
import com.github.nisrulz.sensey.Sensey;
import com.github.nisrulz.sensey.ShakeDetector;
import com.github.nisrulz.sensey.SoundLevelDetector;
import com.github.nisrulz.sensey.StepDetectorUtil;
import com.github.nisrulz.sensey.StepListener;
import com.github.nisrulz.sensey.TiltDirectionDetector;
import com.github.nisrulz.sensey.WaveDetector;
import com.github.nisrulz.sensey.WristTwistDetector;

import java.text.DecimalFormat;
import java.util.Locale;

/**
 * 传感器
 *
 * @since 2021-04-07
 */
public class MainAbility extends Ability implements AbsButton.CheckedStateChangedListener {
    /**
     * 权限
     */
    public static final int REQUEST_CODE = 2;
    private Text tvResult;
    private EventHandler handler;
    private Switch switchShake;
    private Switch switchFlip;
    private Switch switchOrientation;
    private Switch switchProximity;
    private Switch switchLight;
    private Switch switchWave;
    private Switch switchSound;
    private Switch switchMovement;
    private Switch switchChop;
    private Switch switchWrist;
    private Switch switchRotation;
    private Switch switchTilt;
    private Switch switchStep;
    private Switch switchPickup;
    private Switch switchScoop;

    private ShakeDetector.ShakeListener shakeListener;
    private FlipDetector.FlipListener flipListener;
    private OrientationDetector.OrientationListener orientationListener;
    private ProximityDetector.ProximityListener proximityListener;
    private LightDetector.LightListener lightListener;
    private WaveDetector.WaveListener waveListener;
    private SoundLevelDetector.SoundLevelListener soundLevelListener;
    private MovementDetector.MovementListener movementListener;
    private ChopDetector.ChopListener chopListener;
    private WristTwistDetector.WristTwistListener wristTwistListener;
    private RotationAngleDetector.RotationAngleListener rotationAngleListener;
    private TiltDirectionDetector.TiltDirectionListener tiltDirectionListener;
    private StepListener stepListener;
    private PickupDeviceDetector.PickupDeviceListener pickupDeviceListener;
    private ScoopDetector.ScoopListener scoopListener;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);

        WindowManager.getInstance()
            .getTopWindow()
            .get()
            .setStatusBarColor(getColor(ResourceTable.Color_them_color_dark));
        super.setUIContent(ResourceTable.Layout_ability_main);

        handler = new EventHandler(EventRunner.getMainEventRunner());
        initViews();
        setSwitchStyle();
    }

    @Override
    protected void onActive() {
        super.onActive();

        Sensey.getInstance().init();
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        stopAllDetectors();
        setAllSwitchesToFalseState();
        Sensey.getInstance().stop();
    }

    private void setAllSwitchesToFalseState() {
        switchShake.setChecked(false);
        switchFlip.setChecked(false);
        switchOrientation.setChecked(false);
        switchProximity.setChecked(false);
        switchLight.setChecked(false);
        switchWave.setChecked(false);
        switchSound.setChecked(false);
        switchMovement.setChecked(false);
        switchChop.setChecked(false);
        switchWrist.setChecked(false);
        switchRotation.setChecked(false);
        switchTilt.setChecked(false);
        switchStep.setChecked(false);
        switchPickup.setChecked(false);
        switchScoop.setChecked(false);
    }

    private void stopAllDetectors() {
        Sensey.getInstance().stopShakeDetection(shakeListener);
        Sensey.getInstance().stopFlipDetection(flipListener);
        Sensey.getInstance().stopOrientationDetection(orientationListener);
        Sensey.getInstance().stopProximityDetection(proximityListener);
        Sensey.getInstance().stopLightDetection(lightListener);
        Sensey.getInstance().stopWaveDetection(waveListener);
        Sensey.getInstance().stopSoundLevelDetection();
        Sensey.getInstance().stopMovementDetection(movementListener);
        Sensey.getInstance().stopChopDetection(chopListener);
        Sensey.getInstance().stopWristTwistDetection(wristTwistListener);
        Sensey.getInstance().stopRotationAngleDetection(rotationAngleListener);
        Sensey.getInstance().stopTiltDirectionDetection(tiltDirectionListener);
        Sensey.getInstance().stopStepDetection(stepListener);
        Sensey.getInstance().stopPickupDeviceDetection(pickupDeviceListener);
        Sensey.getInstance().stopScoopDetection(scoopListener);
    }

    private void initViews() {
        tvResult = (Text) findComponentById(ResourceTable.Id_tv_result);
        findComponentById(ResourceTable.Id_tv_touch).setClickedListener(component -> {
            Intent intent = new Intent();
            Operation build = new Intent.OperationBuilder()
                .withBundleName(getBundleName())
                .withAbilityName(TouchAbility.class).build();
            intent.setOperation(build);
            startAbility(intent);
        });
        switchShake = (Switch) findComponentById(ResourceTable.Id_switch_shake);
        switchShake.setCheckedStateChangedListener(this);
        switchFlip = (Switch) findComponentById(ResourceTable.Id_switch_flip);
        switchFlip.setCheckedStateChangedListener(this);
        switchOrientation = (Switch) findComponentById(ResourceTable.Id_switch_orientation);
        switchOrientation.setCheckedStateChangedListener(this);
        switchProximity = (Switch) findComponentById(ResourceTable.Id_switch_proximity);
        switchProximity.setCheckedStateChangedListener(this);
        switchLight = (Switch) findComponentById(ResourceTable.Id_switch_light);
        switchLight.setCheckedStateChangedListener(this);
        switchWave = (Switch) findComponentById(ResourceTable.Id_switch_wave);
        switchWave.setCheckedStateChangedListener(this);
        switchSound = (Switch) findComponentById(ResourceTable.Id_switch_sound);
        switchSound.setCheckedStateChangedListener(this);
        switchMovement = (Switch) findComponentById(ResourceTable.Id_switch_movement);
        switchMovement.setCheckedStateChangedListener(this);
        switchChop = (Switch) findComponentById(ResourceTable.Id_switch_chop);
        switchChop.setCheckedStateChangedListener(this);
        switchWrist = (Switch) findComponentById(ResourceTable.Id_switch_wrist);
        switchWrist.setCheckedStateChangedListener(this);
        switchRotation = (Switch) findComponentById(ResourceTable.Id_switch_rotation);
        switchRotation.setCheckedStateChangedListener(this);
        switchTilt = (Switch) findComponentById(ResourceTable.Id_switch_tilt);
        switchTilt.setCheckedStateChangedListener(this);
        switchStep = (Switch) findComponentById(ResourceTable.Id_switch_step);
        switchStep.setCheckedStateChangedListener(this);
        switchPickup = (Switch) findComponentById(ResourceTable.Id_switch_pickup);
        switchPickup.setCheckedStateChangedListener(this);
        switchScoop = (Switch) findComponentById(ResourceTable.Id_switch_scoop);
        switchScoop.setCheckedStateChangedListener(this);

        findComponentById(ResourceTable.Id_layout_shake)
            .setClickedListener(v -> switchShake.setChecked(!switchShake.isChecked()));
        findComponentById(ResourceTable.Id_layout_flip)
            .setClickedListener(v -> switchFlip.setChecked(!switchFlip.isChecked()));
        findComponentById(ResourceTable.Id_layout_orientation)
            .setClickedListener(v -> switchOrientation.setChecked(!switchOrientation.isChecked()));
        findComponentById(ResourceTable.Id_layout_proximity)
            .setClickedListener(v -> switchProximity.setChecked(!switchProximity.isChecked()));
        findComponentById(ResourceTable.Id_layout_light)
            .setClickedListener(v -> switchLight.setChecked(!switchLight.isChecked()));
        findComponentById(ResourceTable.Id_layout_wave)
            .setClickedListener(v -> switchWave.setChecked(!switchWave.isChecked()));
        findComponentById(ResourceTable.Id_layout_sound)
            .setClickedListener(v -> switchSound.setChecked(!switchSound.isChecked()));
        findComponentById(ResourceTable.Id_layout_movement)
            .setClickedListener(v -> switchMovement.setChecked(!switchMovement.isChecked()));
        findComponentById(ResourceTable.Id_layout_chop)
            .setClickedListener(v -> switchChop.setChecked(!switchChop.isChecked()));
        findComponentById(ResourceTable.Id_layout_wrist)
            .setClickedListener(v -> switchWrist.setChecked(!switchWrist.isChecked()));
        findComponentById(ResourceTable.Id_layout_rotation)
            .setClickedListener(v -> switchRotation.setChecked(!switchRotation.isChecked()));
        findComponentById(ResourceTable.Id_layout_tilt)
            .setClickedListener(v -> switchTilt.setChecked(!switchTilt.isChecked()));
        findComponentById(ResourceTable.Id_layout_step)
            .setClickedListener(v -> switchStep.setChecked(!switchStep.isChecked()));
        findComponentById(ResourceTable.Id_layout_pickup)
            .setClickedListener(v -> switchPickup.setChecked(!switchPickup.isChecked()));
        findComponentById(ResourceTable.Id_layout_scoop)
            .setClickedListener(v -> switchScoop.setChecked(!switchScoop.isChecked()));
    }

    private void setSwitchStyle() {
        final int radius = 50;
        final int thumbColor = 0xFFFFFFFF;
        final int trackColor = 0xFF808080;
        ShapeElement elementThumbOn = new ShapeElement();
        elementThumbOn.setShape(ShapeElement.OVAL);
        elementThumbOn.setRgbColor(RgbColor.fromArgbInt(getColor(ResourceTable.Color_accent)));
        elementThumbOn.setCornerRadius(radius);
        ShapeElement elementThumbOff = new ShapeElement();
        elementThumbOff.setShape(ShapeElement.OVAL);
        elementThumbOff.setRgbColor(RgbColor.fromArgbInt(thumbColor));
        elementThumbOff.setCornerRadius(radius);

        ShapeElement elementTrackOn = new ShapeElement();
        elementTrackOn.setShape(ShapeElement.RECTANGLE);
        elementTrackOn.setRgbColor(RgbColor.fromArgbInt(getColor(ResourceTable.Color_divider)));
        elementTrackOn.setCornerRadius(radius);
        ShapeElement elementTrackOff = new ShapeElement();
        elementTrackOff.setShape(ShapeElement.RECTANGLE);
        elementTrackOff.setRgbColor(RgbColor.fromArgbInt(trackColor));
        elementTrackOff.setCornerRadius(radius);

        switchShake.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchShake.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchFlip.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchFlip.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchOrientation.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchOrientation.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchProximity.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchProximity.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchLight.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchLight.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchWave.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchWave.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchSound.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchSound.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchMovement.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchMovement.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchChop.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchChop.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchWrist.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchWrist.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchRotation.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchRotation.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchTilt.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchTilt.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchStep.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchStep.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchPickup.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchPickup.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));

        switchScoop.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchScoop.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));
    }

    private StateElement trackElementInit(ShapeElement on, ShapeElement off) {
        StateElement trackElement = new StateElement();
        trackElement.addState(new int[]{ComponentState.COMPONENT_STATE_CHECKED}, on);
        trackElement.addState(new int[]{ComponentState.COMPONENT_STATE_EMPTY}, off);
        return trackElement;
    }

    private StateElement thumbElementInit(ShapeElement on, ShapeElement off) {
        StateElement thumbElement = new StateElement();
        thumbElement.addState(new int[]{ComponentState.COMPONENT_STATE_CHECKED}, on);
        thumbElement.addState(new int[]{ComponentState.COMPONENT_STATE_EMPTY}, off);
        return thumbElement;
    }

    private boolean checkAudioPermissions() {
        String permission = "ohos.permission.MICROPHONE";
        if (verifySelfPermission(permission) != IBundleManager.PERMISSION_GRANTED) {
            if (canRequestPermission(permission)) {
                requestPermissionsFromUser(new String[]{permission}, 1);
            }
            return false;
        } else {
            return true;
        }
    }

    private boolean checkStepPermissions() {
        String permission = "ohos.permission.ACTIVITY_MOTION";
        if (verifySelfPermission(permission) != IBundleManager.PERMISSION_GRANTED) {
            if (canRequestPermission(permission)) {
                requestPermissionsFromUser(new String[]{permission}, REQUEST_CODE);
            }
            return false;
        } else {
            return true;
        }
    }

    private void setResultTextView(String txt, boolean isRealtime) {
        handler.postTask(() -> {
            tvResult.setText(txt);
            if (!isRealtime) {
                resetResultInView();
            }
        });
    }

    private void resetResultInView() {
        final int time = 3000;
        handler.postTask(() -> {
            tvResult.setText(getString(ResourceTable.String_results_show_here));
        }, time);
    }

    @Override
    public void onCheckedChanged(AbsButton absButton, boolean isCheck) {
        switch (absButton.getId()) {
            case ResourceTable.Id_switch_shake:
                if (isCheck) {
                    Sensey.getInstance().startShakeDetection(getShakeListener());
                } else {
                    Sensey.getInstance().stopShakeDetection(shakeListener);
                }
                break;
            case ResourceTable.Id_switch_flip:
                if (isCheck) {
                    Sensey.getInstance().startFlipDetection(getFlipListener());
                } else {
                    Sensey.getInstance().stopFlipDetection(flipListener);
                }
                break;
            case ResourceTable.Id_switch_orientation:
                if (isCheck) {
                    Sensey.getInstance().startOrientationDetection(getOrientationListener());
                } else {
                    Sensey.getInstance().stopOrientationDetection(orientationListener);
                }
                break;
            case ResourceTable.Id_switch_proximity:
                if (isCheck) {
                    Sensey.getInstance().startProximityDetection(getProximityListener());
                } else {
                    Sensey.getInstance().stopProximityDetection(proximityListener);
                }
                break;
            case ResourceTable.Id_switch_light:
                if (isCheck) {
                    Sensey.getInstance().startLightDetection(getLightListener());
                } else {
                    Sensey.getInstance().stopLightDetection(lightListener);
                }
                break;
            case ResourceTable.Id_switch_wave:
                if (isCheck) {
                    Sensey.getInstance().startWaveDetection(getWaveListener());
                } else {
                    Sensey.getInstance().stopWaveDetection(waveListener);
                }
                break;
            case ResourceTable.Id_switch_sound:
                if (isCheck) {
                    if (checkAudioPermissions()) {
                        Sensey.getInstance().startSoundLevelDetection(this, getSoundLevelListener());
                    } else {
                        switchSound.setChecked(false);
                    }
                } else {
                    Sensey.getInstance().stopSoundLevelDetection();
                }
                break;
            case ResourceTable.Id_switch_movement:
                if (isCheck) {
                    Sensey.getInstance().startMovementDetection(getMovementListener());
                } else {
                    Sensey.getInstance().stopMovementDetection(movementListener);
                }
                break;
            case ResourceTable.Id_switch_chop:
                if (isCheck) {
                    Sensey.getInstance().startChopDetection(getChopListener());
                } else {
                    Sensey.getInstance().stopChopDetection(chopListener);
                }
                break;
            case ResourceTable.Id_switch_wrist:
                if (isCheck) {
                    Sensey.getInstance().startWristTwistDetection(getWristTwistListener());
                } else {
                    Sensey.getInstance().stopWristTwistDetection(wristTwistListener);
                }
                break;
            case ResourceTable.Id_switch_rotation:
                if (isCheck) {
                    Sensey.getInstance().startRotationAngleDetection(getRotationAngleListener());
                } else {
                    Sensey.getInstance().stopRotationAngleDetection(rotationAngleListener);
                }
                break;
            case ResourceTable.Id_switch_tilt:
                if (isCheck) {
                    Sensey.getInstance().startTiltDirectionDetection(getTiltDirectionListener());
                } else {
                    Sensey.getInstance().stopTiltDirectionDetection(tiltDirectionListener);
                }
                break;
            case ResourceTable.Id_switch_step:
                if (isCheck) {
                    if (checkStepPermissions()) {
                        Sensey.getInstance().startStepDetection(this, getStepListener(), StepDetectorUtil.MALE);
                    } else {
                        switchStep.setChecked(false);
                    }
                } else {
                    Sensey.getInstance().stopStepDetection(stepListener);
                }
                break;
            case ResourceTable.Id_switch_pickup:
                if (isCheck) {
                    Sensey.getInstance().startPickupDeviceDetection(getPickupDeviceListener());
                } else {
                    Sensey.getInstance().stopPickupDeviceDetection(pickupDeviceListener);
                }
                break;
            case ResourceTable.Id_switch_scoop:
                if (isCheck) {
                    Sensey.getInstance().startScoopDetection(getScoopListener());
                } else {
                    Sensey.getInstance().stopScoopDetection(scoopListener);
                }
                break;
            default:
                break;
        }
    }

    private ShakeDetector.ShakeListener getShakeListener() {
        if (shakeListener == null) {
            shakeListener = new ShakeDetector.ShakeListener() {
                @Override
                public void onShakeDetected() {
                    setResultTextView("Shake Detected!", false);
                }

                @Override
                public void onShakeStopped() {
                    setResultTextView("Shake Stopped!", false);
                }
            };
        }
        return shakeListener;
    }

    private FlipDetector.FlipListener getFlipListener() {
        if (flipListener == null) {
            flipListener = new FlipDetector.FlipListener() {
                @Override
                public void onFaceDown() {
                    setResultTextView("Face Down", false);
                }

                @Override
                public void onFaceUp() {
                    setResultTextView("Face UP", false);
                }
            };
        }
        return flipListener;
    }

    private OrientationDetector.OrientationListener getOrientationListener() {
        if (orientationListener == null) {
            orientationListener = new OrientationDetector.OrientationListener() {
                @Override
                public void onBottomSideUp() {
                    setResultTextView("Bottom Side UP", false);
                }

                @Override
                public void onLeftSideUp() {
                    setResultTextView("Left Side UP", false);
                }

                @Override
                public void onRightSideUp() {
                    setResultTextView("Right Side UP", false);
                }

                @Override
                public void onTopSideUp() {
                    setResultTextView("Top Side UP", false);
                }
            };
        }
        return orientationListener;
    }

    private ProximityDetector.ProximityListener getProximityListener() {
        if (proximityListener == null) {
            proximityListener = new ProximityDetector.ProximityListener() {
                @Override
                public void onFar() {
                    setResultTextView("Far", false);
                }

                @Override
                public void onNear() {
                    setResultTextView("Near", false);
                }
            };
        }
        return proximityListener;
    }

    private LightDetector.LightListener getLightListener() {
        if (lightListener == null) {
            lightListener = new LightDetector.LightListener() {
                @Override
                public void onDark() {
                    setResultTextView("Dark", false);
                }

                @Override
                public void onLight() {
                    setResultTextView("Not Dark", false);
                }
            };
        }
        return lightListener;
    }

    private WaveDetector.WaveListener getWaveListener() {
        if (waveListener == null) {
            waveListener = () -> setResultTextView("Wave Detected!", false);
        }
        return waveListener;
    }

    private SoundLevelDetector.SoundLevelListener getSoundLevelListener() {
        if (soundLevelListener == null) {
            soundLevelListener = level -> {
                String db = new DecimalFormat("##.##").format(level);
                String data = db + "dB";
                setResultTextView(data, true);
            };
        }
        return soundLevelListener;
    }

    private MovementDetector.MovementListener getMovementListener() {
        if (movementListener == null) {
            movementListener = new MovementDetector.MovementListener() {
                @Override
                public void onMovement() {
                    setResultTextView("Movement Detected!", false);
                }

                @Override
                public void onStationary() {
                    setResultTextView("Device Stationary!", false);
                }
            };
        }
        return movementListener;
    }

    private ChopDetector.ChopListener getChopListener() {
        if (chopListener == null) {
            chopListener = () -> setResultTextView("Chop Detected!", false);
        }
        return chopListener;
    }

    private WristTwistDetector.WristTwistListener getWristTwistListener() {
        if (wristTwistListener == null) {
            wristTwistListener = () -> setResultTextView("Wrist Twist Detected!", false);
        }
        return wristTwistListener;
    }

    private RotationAngleDetector.RotationAngleListener getRotationAngleListener() {
        if (rotationAngleListener == null) {
            rotationAngleListener = (angleInAxisX, angleInAxisY, angleInAxisZ) -> {
                String data = String.format(Locale.ROOT,"Rotation in Axis Detected(deg):\nX=%f,\nY=%f,\nZ=%f",
                    angleInAxisX, angleInAxisY, angleInAxisZ);
                setResultTextView(data, true);
            };
        }
        return rotationAngleListener;
    }

    private TiltDirectionDetector.TiltDirectionListener getTiltDirectionListener() {
        if (tiltDirectionListener == null) {
            tiltDirectionListener = new TiltDirectionDetector.TiltDirectionListener() {
                @Override
                public void onTiltInAxisX(int direction) {
                    displayResultForTiltDirectionDetector(direction, "X");
                }

                @Override
                public void onTiltInAxisY(int direction) {
                    displayResultForTiltDirectionDetector(direction, "Y");
                }

                @Override
                public void onTiltInAxisZ(int direction) {
                    displayResultForTiltDirectionDetector(direction, "Z");
                }
            };
        }
        return tiltDirectionListener;
    }

    private void displayResultForTiltDirectionDetector(int direction, String axis) {
        String dir = direction == TiltDirectionDetector.DIRECTION_CLOCKWISE
            ? "ClockWise" : "AntiClockWise";
        setResultTextView(String.format(Locale.ROOT,"Tilt in %s Axis: %s", axis, dir), false);
    }

    private StepListener getStepListener() {
        if (stepListener == null) {
            stepListener = (noOfSteps, distanceInMeter, stepActivityType) -> {
                String typeOfActivity = null;
                if (stepActivityType == StepDetectorUtil.ACTIVITY_RUNNING) {
                    typeOfActivity = "Running";
                } else if (stepActivityType == StepDetectorUtil.ACTIVITY_WALKING) {
                    typeOfActivity = "Walking";
                } else {
                    typeOfActivity = "Still";
                }
                String data = String.format(Locale.ROOT,"Steps: %d\nDistance: %f m\nActivity Type: %s",
                    noOfSteps, distanceInMeter, typeOfActivity);
                setResultTextView(data, true);
            };
        }
        return stepListener;
    }

    private PickupDeviceDetector.PickupDeviceListener getPickupDeviceListener() {
        if (pickupDeviceListener == null) {
            pickupDeviceListener = new PickupDeviceDetector.PickupDeviceListener() {
                @Override
                public void onDevicePickedUp() {
                    setResultTextView("Device Picked up Detected!", false);
                }

                @Override
                public void onDevicePutDown() {
                    setResultTextView("Device Put down Detected!", false);
                }
            };
        }
        return pickupDeviceListener;
    }

    private ScoopDetector.ScoopListener getScoopListener() {
        if (stepListener == null) {
            scoopListener = () -> setResultTextView("Scoop Gesture Detected!", false);
        }
        return scoopListener;
    }
}
